package LevelEditor;

import javax.swing.JButton;
import javax.swing.JFormattedTextField;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ScrollPaneConstants;

import Objects.GameObject;
import GameEngine.GameConstants;
import GameEngine.GameConstants.*;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.NumberFormat;
import java.util.Iterator;
import java.util.List;

/**
 * Panel for "tools" like those in MS Paint including:
 * Buttons, one for each type of object.
 * Buttons, one for each direction.
 * Modifiers for the size of the level.
 * @author jh20
 *
 */

public class ToolPanel extends JPanel {
	
	/**
	 * A constructor.
	 */
	
	private final int button_row = 3; // number of buttons in one row
	
	private MainPanel mainPanel;
	
	private JFormattedTextField xField, yField, numPlayerField;
	
	public ToolPanel(MainPanel mp) {
		super();
		mainPanel = mp;
		
		this.setLayout(new BorderLayout());
		this.add(getObjButtons(), BorderLayout.CENTER);
		this.add(getDirButtons(), BorderLayout.SOUTH);

        JPanel fieldPanel = new JPanel();
        fieldPanel.setLayout(new BorderLayout());
        fieldPanel.add(getSizePanel(), BorderLayout.CENTER);
        fieldPanel.add(getNumPlayerPanel(), BorderLayout.SOUTH);
		this.add(fieldPanel, BorderLayout.NORTH);

		this.setSize(new Dimension(EditorConstants.TOOL_SIZE_X, EditorConstants.TOOL_SIZE_Y));
		
	}
	
	/**
	 * Factory method that returns a JPanel with a button for each type of object.
	 * @param it	An iterator over all gameobjects
	 * @param size	Number of gameobject types that exist
	 * @return
	 */
	
	public JPanel getObjButtons() {
		JPanel miniP = new JPanel();
		miniP.setLayout(new GridLayout((GameConstants.Thing.values().length - GameConstants.SPECIAL_TYPES)/button_row + 1, button_row));

		for (int i = 0; i < Thing.values().length - GameConstants.SPECIAL_TYPES; i++) {
            Thing type = Thing.values()[i];
			
			JButton objectButton = new JButton(type.toString());
			objectButton.addActionListener(new ButtonListener(type));
			miniP.add(objectButton);
		}

        // wall button
        JButton wallButton = new JButton("WALL*");
        wallButton.addActionListener(new ButtonListener(Thing.WALL));
        miniP.add(wallButton);
		
		JScrollPane buttonScroll = new JScrollPane(miniP);
		buttonScroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
		buttonScroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
		
		// space things out
		JPanel buttonP = EditorFunctions.getSpace(buttonScroll);
		
		JLabel objects = new JLabel("Objects");
		objects.setHorizontalAlignment(getWidth()/2);
		buttonP.add(objects, BorderLayout.NORTH);

        JLabel special = new JLabel("(Objects with a * require two clicks, for two opposing ends.)");
        special.setFont(new Font(special.getFont().getFontName(), Font.ITALIC, 9));
        special.setHorizontalAlignment(special.getWidth()/2);
        buttonP.add(special, BorderLayout.SOUTH);

        
		
		return buttonP;
	}
	
	/**
	 * Factory method that returns a JPanel with a button for each cardinal direction of rotation
	 * @return
	 */
	
	public JPanel getDirButtons() {
		JPanel miniP = new JPanel();
		miniP.setLayout(new GridLayout(3,3));
		Modifier[] listDirs = Modifier.values();
		for (int i = 0; i < 4; i++) {
			JButton dirButton = new JButton(listDirs[i].name());
			dirButton.addActionListener(new DirListener(listDirs[i]));
			miniP.add(dirButton);
		}

        miniP.add(new JPanel());

        for (int i = 4; i < listDirs.length; i++) {
			JButton dirButton = new JButton(listDirs[i].name());
			dirButton.addActionListener(new DirListener(listDirs[i]));
			miniP.add(dirButton);
		}
		
		// space things out
		JPanel dirP = EditorFunctions.getSpace(miniP);
		JLabel directions = new JLabel("Directions");
		directions.setHorizontalAlignment(directions.getWidth()/2);
		dirP.add(directions, BorderLayout.NORTH);
		
		return dirP;
	}
	
	/**Object srouce = arg0.
	 * Factor method that returns a JPanel that allows the user to change the size of the level.
	 * 
	 */
	
	public JPanel getSizePanel() {
		JPanel sizeP = new JPanel();
		JPanel miniP = new JPanel();
		sizeP.setLayout(new BorderLayout());
		
		miniP.setLayout(new GridLayout(2, 2));
		
		NumberFormat numFormat = NumberFormat.getIntegerInstance();
		numFormat.setMaximumIntegerDigits(4);
		numFormat.setParseIntegerOnly(true);
		
		SizeListener sizeL = new SizeListener(); 
		
		miniP.add(new JLabel("Width : "));
		xField = new JFormattedTextField(numFormat);
		xField.setValue(mainPanel.getSizeX());
		xField.addPropertyChangeListener(sizeL);
		miniP.add(xField);

		miniP.add(new JLabel("Height : "));
		yField = new JFormattedTextField(numFormat);
		yField.setValue(mainPanel.getSizeY());
		yField.addPropertyChangeListener(sizeL);
		miniP.add(yField);
		
		JLabel levelSize = new JLabel("Level size");
		levelSize.setHorizontalAlignment(levelSize.getWidth()/2);
		sizeP.add(levelSize, BorderLayout.NORTH);
		sizeP.add(miniP, BorderLayout.CENTER);
		
		return EditorFunctions.getSpace(sizeP);
	}

    /**
     * Factory method, returns a panel that allows specification of the number of
     * players
     * @return
     */

    public JPanel getNumPlayerPanel() {
        JPanel miniP = new JPanel();
        miniP.setLayout(new GridLayout(1, 2));

        NumberFormat numFormat = NumberFormat.getIntegerInstance();
		numFormat.setMaximumIntegerDigits(1);
		numFormat.setParseIntegerOnly(true);

        NumPlayerListener numL = new NumPlayerListener();

        miniP.add(new JLabel("Players : "));
        numPlayerField = new JFormattedTextField(numFormat);
        numPlayerField.setValue(mainPanel.getNumPlayers());
        numPlayerField.addPropertyChangeListener(numL);
        miniP.add(numPlayerField);

        return EditorFunctions.getSpace(miniP);
    }

    /**
     * Changes the values of the text fields
     * I don't want to automatically reset the field when it's empty, so there's that
     * boolean there
     * @param x
     * @param y
     */

    public void setSizeFields(int x, int y) {
        if (xField.getText().length() > 1) {
            xField.setValue(x);
        }
        if (yField.getText().length() > 1) {
            yField.setValue(y);
        }
    }

    public void setNumPlayerField(int n) {
        if (!numPlayerField.getText().isEmpty()) {
            numPlayerField.setValue(n);
        }
    }
	
	/**
	 * ActionListener for the object buttons
	 * Sets the current object type to be that of the button
	 * @author jh20
	 *
	 */
	
	private class ButtonListener implements ActionListener {
		
		private GameConstants.Thing buttonObjType;
		
		public ButtonListener(Thing t) {
			super();
			
			buttonObjType = t;
		}

		@Override
		public void actionPerformed(ActionEvent arg0) {
			mainPanel.setCurrentType(buttonObjType);

            // reset first click since we changed types
			mainPanel.resetFirstClick();
		}
		
	}
	
	/**
	 * Action listener for the directional buttons
	 * Sets the current direction to be that of the button
	 * @author jh20
	 *
	 */
	
	private class DirListener implements ActionListener {
		private GameConstants.Modifier dir;
		
		public DirListener(GameConstants.Modifier m) {
			super();
			
			dir = m;
		}
		
		@Override
		public void actionPerformed(ActionEvent arg0) {
			mainPanel.setDir(dir);
		}
	}
	
	/**
	 * PropertyChangeListener for changing the size of the level
	 * @author jh20
	 *
	 */
	
	private class SizeListener implements PropertyChangeListener {
		
		public SizeListener() {
			super();
		}

		@Override
		public void propertyChange(PropertyChangeEvent arg0) {
			Object source = arg0.getSource();
			if (source == xField) {
				int newSize = ((Number) xField.getValue()).intValue();
				mainPanel.setLevelSize(newSize, mainPanel.getSizeY());
			} else if (source == yField) {
				int newSize = ((Number) yField.getValue()).intValue();
				mainPanel.setLevelSize(mainPanel.getSizeX(), newSize);
			}
			
		}
			
	}

    /**
     * PropertyChangeListener for changing the number of players for a level
     */

    private class NumPlayerListener implements PropertyChangeListener {

        public NumPlayerListener() {
            super();
        }

        @Override
        public void propertyChange(PropertyChangeEvent arg0) {
            int newNumPlayers = ((Number) numPlayerField.getValue()).intValue();
            if (newNumPlayers != mainPanel.getNumPlayers()) {
                mainPanel.setNumPlayers(newNumPlayers);
            }
        }
    }
	
	
}
